import type {
  Component,
  CSSProperties,
  VNode,
  Fragment,
  Teleport,
  Suspense,
  KeepAlive,
  TransitionGroup,
  SetupContext,
  FunctionalComponent,
} from "vue";


export namespace IElsElem {
  export interface Props {
    elem: Elem;
    context?: Context;
    parent?: Parent;
    params?: Record<string, any>;
    slotParams?: any;
    slots?: any;
  }
  export type Parent = Record<string, any> & {
    elem: Elem;
    setupRes: ReturnType<SetupFunction>;
    tagname: string;
  }
  export interface Elem extends Record<string,any> {
    tag?: TOR<StaticTag>;
    style?: TOR<string | CSSProperties>;
    contextKeys?: string[];
    excludeKeys?: string[];
    cls?: TORA<Child>;
    children?: TORA<Child>;
    setup?: SetupFunction;
    render?: RenderFunction;
    beforeRender?: (scope: ScopeData) => void;
    isDirectRender?: boolean;
  }

  export interface Context extends Record<string,any> {
    slots?: Record<string, RenderFunction>;
    tag?: Tag;
    contextKeys?: Elem["contextKeys"];
    excludeKeys?: Elem["excludeKeys"];
    setup?: SetupFunction;
    render?: RenderFunction | Record<string, RenderFunction>;
    beforeRender?: Elem["beforeRender"];
    params?:Record<string,any>
  }

  export type Tag = StaticTag | FunctionTag;
  //
  export type StaticTag =
    | keyof HTMLElementTagNameMap
    | "slot"
    | "template"
    | "component"
    | Component
    | InstanceType<typeof Fragment>
    | InstanceType<typeof Teleport>
    | InstanceType<typeof Suspense>
    | InstanceType<typeof KeepAlive>
    | FunctionalComponent
    | InstanceType<typeof TransitionGroup>;

  export type FunctionTag = (params:Record<string,any> & Props & {tag?:any},ctx: SetupContext) => StaticTag;

  export type Child =
    | string
    | boolean
    | number
    | VNode
    | Elem
    | ((
        scope: Record<string, any>,
        slotScope: any,
        elemScope: ScopeData
      ) => string | VNode | undefined);

  export type SetupFunction = (
    props: Props,
    params: { tag: StaticTag; tagname: string; isHtml: boolean },
    ctx: SetupContext
  ) =>
    | (Record<string, any> & {
        prop?: Record<string, any>;
        render?:
          | RenderFunction
          | Record<string, RenderFunction>;
        beforeRender?: (scope: ScopeData) => void;
        excludeKeys?: string[];
      })
    | void;

  
    export type RenderFunction = (
      config: RenderFunctionParams
    ) => TOA<string | VNode> | undefined;

    export interface RenderFunctionParams {
      tag: Tag;
      tagname: string;
      isHtml: boolean;
      props: any;
      children: Record<string, (p?: any) => TOA<string | VNode> | undefined>;
      elem: Elem;
      context: Context;
      slots: any;
      parent: Props["parent"];
      directives: Record<string, any>;
      setupRes: Record<string, any>;
    }

    export interface ScopeData extends Record<string, any> {
      $tag: Tag;
      $tagname: string;
      $isHtml: boolean;
      $slots: any;
      $elem: Elem;
      $context: Context;
      $root: Record<string, any>;
      $prop: Record<string, any>;
      $directive: Record<string, any>;
      $params: Record<string, any>;
      $setupRes: ReturnType<SetupFunction>;
      $elemSetupRes: ReturnType<SetupFunction>;
      $ctxSetupRes: ReturnType<SetupFunction>;
      $parent: Props["parent"];
    }

    export interface Attrs {
      root: Partial<Elem>;
      directive: Partial<Elem>;
      prop: Partial<Elem>;
      ctx:Record<any,any>
    }
}
